package Serveur;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;

import Both.Trajet;
import Both.Transport;
import Both.Ville;

/**
 * Une reservation permet de sauvegarder un nombre de personne pour un certain
 * trajet a une certain date.
 * 
 * @author user
 * 
 */
public class Reservation {
    private Trajet trajet;
    private GregorianCalendar date;
    private int nbPersonne;

    /**
     * Constructeur par defaut (pour le XML)
     */
    public Reservation() {
    }

    /**
     * Constructeur normal
     * 
     * @param trajet
     * @param nbPersonne
     */
    public Reservation(Trajet trajet, int nbPersonne) throws RuntimeException {

        if (nbPersonne > 0 && trajet.getNbPlaceDispo() >= nbPersonne) {
            this.trajet = trajet;
            this.date = new GregorianCalendar();
            this.nbPersonne = nbPersonne;
            this.trajet.addReservation(nbPersonne);
        } else {
            new RuntimeException("Parametres invalides");
        }

    }

    /**
     * Savoir si on peut reserver entre deux villes � certaine dates pour un
     * certain nombre de personne
     * 
     * @param ListeTrajets
     * @param villeDepart
     * @param villeArrive
     * @param datedepart
     * @param dateArrive
     * @param nbPersonne
     * @return Liste de trajet correspondant
     * @throws NoPlaceReservationException
     */
    public static ArrayList<Trajet> peutReserver(
            ArrayList<Trajet> ListeTrajets, Ville villeDepart,
            Ville villeArrive, GregorianCalendar datedepart,
            GregorianCalendar dateArrive, Transport t, int nbPersonne)
            throws NoPlaceReservationException {

        // Opposer le nombre de personne si la valeur est negative
        if (nbPersonne < 0) {
            nbPersonne = -nbPersonne;
        }

        // Filtrer la liste des trajets
        ArrayList<Trajet> ListeTrajetfiltrer = Trajet.searchTrajet(
                ListeTrajets, villeDepart, villeArrive, datedepart, dateArrive,
                t, nbPersonne);
        ArrayList<Trajet> ListeNewTrajet = new ArrayList<Trajet>();
        int maxPlacedispo = 0;

        if (!ListeTrajetfiltrer.isEmpty()) {
            Iterator<Trajet> it = ListeTrajetfiltrer.iterator();
            while (it.hasNext()) {
                Trajet current = it.next();
                if (current.peutReserver(nbPersonne)) {
                    ListeNewTrajet.add(current);
                } else {
                    if (current.getNbPlaceDispo() > maxPlacedispo) {
                        maxPlacedispo = current.getNbPlaceDispo();
                    }
                }
            }

            // Si le nombre de trajet trouv�
            if (ListeNewTrajet.isEmpty()) {
                throw new NoPlaceReservationException(maxPlacedispo);
            }
            return ListeNewTrajet;
        } else {
            throw new NoPlaceReservationException(maxPlacedispo);
        }
    }

    /**
     * Savoir si on peut reserver pour in certain trajet
     * 
     * @param ListeTrajets
     * @param t
     * @param nbpers
     * @return true si la reservation est possible false sinon
     * @throws NoPlaceReservationException
     */
    public static boolean peutReserver(ArrayList<Trajet> ListeTrajets,
            Trajet t, int nbpers) {
        // Opposer le nombre de personne si la valeur est negative
        if (nbpers < 0) {
            nbpers = -nbpers;
        }

        ArrayList<Trajet> ListeTrajFiltre;
        try {
            ListeTrajFiltre = peutReserver(ListeTrajets, t.getVilleDepart(), t
                    .getVilleArrive(), t.getDateDepart(), t.getDateArrive(), t
                    .getTransport(), nbpers);
        } catch (NoPlaceReservationException e) {
            // TODO Auto-generated catch block
            return false;
        }
        return !ListeTrajFiltre.isEmpty();
    }

    /**
     * Savoir si on peut reserver avec un reservation
     * 
     * @return true si la reservation est possible false sinon
     * @throws NoPlaceReservationException
     */
    public boolean peutReserver(Serveur serv) {
        return peutReserver(serv.getListeTrajet(), this.trajet, this.nbPersonne);
    }

    /**
     * Effectuer un reservation pour un trajet et un nombre de personne
     * 
     * @param ListeTrajets
     * @param t
     * @param nbpers
     * @return vrai si la reservation est possible faux sinon
     * @throws NoPlaceReservationException
     */
    public static boolean Reserver(Serveur serv, Trajet t, int nbpers) {

        // Opposer le nombre de personne si la valeur est negative
        if (nbpers < 0) {
            nbpers = -nbpers;
        }

        ArrayList<Trajet> ListeFiltreTrajet;
        try {
            ListeFiltreTrajet = peutReserver(serv.getListeTrajet(), t
                    .getVilleDepart(), t.getVilleArrive(), t.getDateDepart(), t
                    .getDateArrive(), t.getTransport(), nbpers);
        } catch (NoPlaceReservationException e) {
            return false;
        }

        Iterator<Trajet> it = ListeFiltreTrajet.iterator();

        if (!ListeFiltreTrajet.isEmpty()) {
            // choisir le premier trajet disponible
            Trajet traj = it.next();

            int index = serv.getListeTrajet().indexOf(traj);
            traj.reserver(nbpers);

            // Modifier le trajet dans la liste du serveur
            serv.getListeTrajet().set(index, traj);

            // Ajouter la reservation dans la liste des reservations
            serv.addReservation(new Reservation(traj, nbpers));

            return true;
        } else {
            return false;
        }
    }

    /**
     * Reserver pour une reservation donn�e Ajout de la reservation dans la
     * liste du serveur
     * 
     * @return
     * @throws NoPlaceReservationException
     */
    public boolean Reserver(Serveur serv) {
        return Reserver(serv, trajet, nbPersonne);
    }

    @Override
    public String toString() {
        String retour = "";
        retour += "Trajet : " + trajet.toString();
        retour += "\nDate : " + getFormatedDate(date.getTime());
        retour += "\nNb place reserve : " + nbPersonne;
        retour += "\n";

        return retour;
    }

    /**
     * Retourne la date formatee en String
     * 
     * @param Date
     *            d
     * @return String
     */
    public String getFormatedDate(Date d) {

        DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy 'a�' HH:mm");
        return dateFormat.format(d);
    }

    public void print() {
        System.out.println(toString());
    }

    /**
     * Redefinition de la methode equals
     */
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Reservation)) {
            return false;
        }

        Reservation Res = (Reservation) obj;

        if (!this.date.equals(Res.date)) {
            return false;
        }
        if (this.nbPersonne != Res.nbPersonne) {
            return false;
        }
        if (!this.trajet.equals(Res.trajet)) {
            return false;
        }
        return true;
    };

    /**
     * Annuler une reservation
     * 
     * @param ListeReservation
     * @param R
     * @return vrai si l'annulation a pu se faire
     */
    public static boolean annuler(ArrayList<Reservation> ListeReservation,
            Reservation R) {
        if (!ListeReservation.contains(R)) {
            System.out
                    .println("La reservation n'est pas presente dans la liste");
            return false;
        }

        // Supprimer la reservation de la liste des reservations dans le serveur
        ListeReservation.remove(R);

        // Remettre le nombre de place disponible.
        Trajet traj = R.getTrajet();
        int placeReserve = R.getNbPersonne();
        if (!traj.annulerReservation(placeReserve)) {
            System.out.println("Impossible de supprimer la reservation");
        }

        return true;
    }

    /**
     * Rechercher une reservation par trajet et date
     * 
     * @param ListeReservation
     * @param trajet
     * @param date
     * @return Liste de reservation correpondante
     */
    public static ArrayList<Reservation> searchReservation(
            ArrayList<Reservation> ListeReservation, Trajet trajet,
            GregorianCalendar date) {
        ArrayList<Reservation> ListeReservationRetour = new ArrayList<Reservation>();
        Iterator<Reservation> it = ListeReservation.iterator();

        while (it.hasNext()) {
            Reservation current = it.next();
            if (current.getDate().equals(date)
                    && current.getTrajet().equals(trajet)) {
                ListeReservationRetour.add(current);
            }
        }

        return ListeReservationRetour;
    }

    /**
     * Acceseur de consultation
     * 
     * @return Trajet
     */
    public Trajet getTrajet() {
        return trajet;
    }

    public void setTrajet(Trajet t) {
        this.trajet = t;
    }

    /**
     * Accesseur pour obtenir la date
     * 
     * @return Date
     */
    public GregorianCalendar getDate() {
        return date;
    }

    public void setDate(GregorianCalendar date) {
        this.date = date;
    }

    /**
     * Accesseur pour obtenir le nombre de personne
     * 
     * @return nombre de personne int
     */
    public int getNbPersonne() {
        return nbPersonne;
    }

    public void setNbPersonne(int nb) {
        this.nbPersonne = nb;
    }
}
